package jenkins

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"gitee.com/laofa1/play/k_conf_mng/kconf_backend/pkg/setting"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

type Crumb struct {
	Class string `json:"_class"`
	Crumb string `json:"crumb"`
	CrumbRequestField string `json:"crumbRequestField"`
}

type ViewCreateParam struct {
	Name string `json:"name"`
	Mode string `json:"mode"`
	Crumb string `json:"Jenkins-Crumb"`
	Submit string `json:"Submit"`
}

type ViewDeleteParam struct {
	Crumb string `json:"Jenkins-Crumb"`
}

type OutViewCreateParam struct {
	Name string `json:"name"`
	Mode string `json:"mode"`
	Crumb string `json:"Jenkins-Crumb"`
	Submit string `json:"Submit"`
	Json []byte `json:"json"`
}

func IsJenkinsViewExists(envName string) (bool, error) {
	BasicAuth := base64.StdEncoding.EncodeToString([]byte(setting.JenkinsUser + ":" + setting.JenkinsPassword))
	checkUri := setting.JenkinsApiBase + "/view/" + strings.ToUpper(envName) + "/config.xml"
	req, err := http.NewRequest("GET", checkUri, nil)
	if err != nil {
		log.Println(err)
		return false, err
	}

	req.Header.Set("Authorization", "Basic " + BasicAuth)
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Println(err)
		return false, err
	}
	if resp.StatusCode == 404 {
		return false, nil
	} else if resp.StatusCode != 200 {
		errMsg := fmt.Sprintf("query view: %s, error: response not 200 or 404", envName)
		log.Println(errMsg)
		return false, errors.New(errMsg)
	} else {
		return true, nil
	}
}

func GetCrumb(auth string) (Crumb, error) {
	getCrumbUri := setting.JenkinsApiBase + "/crumbIssuer/api/json"

	// get jenkins crumb
	req, err := http.NewRequest("GET", getCrumbUri, nil)
	if err != nil {
		log.Println(err)
		return Crumb{}, err
	}
	req.Header.Set("Authorization", "Basic " + auth)
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Println(err)
		return Crumb{}, err
	}
	defer func() {
		if err := resp.Body.Close(); err != nil {
			log.Println(err)
		}
	}()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Println(err)
		return Crumb{}, err
	}

	if resp.StatusCode != 200 {
		log.Println(body)
		return Crumb{}, errors.New("fail to get jenkins crumb, return code: " + strconv.Itoa(resp.StatusCode))
	}

	var crumb Crumb
	err = json.Unmarshal(body, &crumb)
	if err != nil {
		log.Println(err)
		return Crumb{}, err
	}
	return crumb, nil
}

func CreateView(envName string) error {
	BasicAuth := base64.StdEncoding.EncodeToString([]byte(setting.JenkinsUser + ":" + setting.JenkinsPassword))

	// get crumb
	crumb, err := GetCrumb(BasicAuth)
	if err != nil {
		log.Println(err)
		return err
	}

	// create view
	createUri := setting.JenkinsApiBase + "/createView"
	viewCreateParam := ViewCreateParam{
		Name: strings.ToUpper(envName),
		Mode: "hudson.model.ListView",
		Crumb: crumb.Crumb,
		Submit: "OK",
	}
	outJson, err := json.Marshal(viewCreateParam)
	if err != nil {
		log.Println(err)
		return err
	}

	data := url.Values{}
	data.Set("name", viewCreateParam.Name)
	data.Set("mode", viewCreateParam.Mode)
	data.Set("Jenkins-Crumb", viewCreateParam.Crumb)
	data.Set("json", string(outJson))
	data.Set("Submit", viewCreateParam.Submit)
	// log.Println(data.Encode())
	reqView, err := http.NewRequest("POST", createUri, strings.NewReader(data.Encode()))
	if err != nil {
		log.Println(err)
		return err
	}

	reqView.Header.Add("Authorization", "Basic " + BasicAuth)
	reqView.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	reqView.Header.Add("Content-Length", strconv.Itoa(len(data.Encode())))

	// req.Header.Add(crumb.CrumbRequestField, crumb.Crumb)
	clientView := &http.Client{
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return http.ErrUseLastResponse
		},
	}
	respView, err := clientView.Do(reqView)
	if err != nil {
		log.Println(err)
		return err
	}
	defer func() {
		if err := respView.Body.Close(); err != nil {
			log.Println(err)
		}
	}()
	if respView.StatusCode != 302 {
		errMsg := fmt.Sprintf("fail to creating jenkins view: %s, return code: %d", envName, respView.StatusCode)
		log.Println(errMsg)
		message, _ := ioutil.ReadAll(respView.Body)
		log.Println(string(message))
		return errors.New(errMsg)
	}
	return nil
}

func DeleteView(envName string) error {
	BasicAuth := base64.StdEncoding.EncodeToString([]byte(setting.JenkinsUser + ":" + setting.JenkinsPassword))

	// get crumb
	crumb, err := GetCrumb(BasicAuth)
	if err != nil {
		log.Println(err)
		return err
	}

	// delete view
	createUri := setting.JenkinsApiBase + "/view/" + strings.ToUpper(envName) + "/doDelete"
	viewCreateParam := ViewDeleteParam{
		Crumb: crumb.Crumb,
	}
	outJson, err := json.Marshal(viewCreateParam)
	if err != nil {
		log.Println(err)
		return err
	}

	data := url.Values{}
	data.Set("Jenkins-Crumb", viewCreateParam.Crumb)
	data.Set("json", string(outJson))
	data.Set("Submit", "Yes")
	reqView, err := http.NewRequest("POST", createUri, strings.NewReader(data.Encode()))
	if err != nil {
		log.Println(err)
		return err
	}

	reqView.Header.Add("Authorization", "Basic " + BasicAuth)
	reqView.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	reqView.Header.Add("Content-Length", strconv.Itoa(len(data.Encode())))

	// req.Header.Add(crumb.CrumbRequestField, crumb.Crumb)
	clientView := &http.Client{
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return http.ErrUseLastResponse
		},
	}
	respView, err := clientView.Do(reqView)
	if err != nil {
		log.Println(err)
		return err
	}
	defer func() {
		if err := respView.Body.Close(); err != nil {
			log.Println(err)
		}
	}()
	if respView.StatusCode == 404 {
		return nil
	} else if respView.StatusCode != 302 && respView.StatusCode != 200 && respView.StatusCode != 204 {
		errMsg := fmt.Sprintf("fail to delete jenkins view: %s, return code: %d", envName, respView.StatusCode)
		log.Println(errMsg)
		message, _ := ioutil.ReadAll(respView.Body)
		log.Println(string(message))
		return errors.New(errMsg)
	}
	return nil
}